import { Scene } from "./scene.js"

const KEY_MAPS = {
    Space: "space",
    ArrowRight: "right arrow",
    ArrowLeft: "left arrow",
    ArrowUp: "up arrow",
    ArrowDown: "down arrow",
    Enter: "enter",
    Plus: "+",
    Minus: "-",
};

var char = str => str.charCodeAt(0);

// generate character keys
for (let n = char("a"); n < char("z"); n++) {
    let c = String.fromCharCode(n);
    KEY_MAPS["Key" + c.toUpperCase()] = c;
}

// generate number keys
for (let i = 0; i < 9; i++) {
    KEY_MAPS["Key" + i] = i.toString();
}

console.log(KEY_MAPS);

class Project {
    constructor(canvas) {
        this.mouseX = 0;
        this.mouseY = 0;
        this._mouseDown = false;
        this.keys = new Set();
        
        this.canvas = canvas;

        this.reset();
    }

    async loadXml(xml, shared) {
        if (xml.nodeName !== "project") throw new Error("Expected <project> tag");
        
        for (let node of xml.children) {
            if (node.nodeName === "scenes") {
               // create scenes
               for (let sceneNode of node.children) {
                   var scene = new Scene(this);
                   scene.loadXml(sceneNode, shared);
                   this.scenes.push(scene);
               } 
            }
        }

        this.updateSize();
    }

    reset() {
        this.scenes = [];
        this.sceneNum = 0;
        this.scheduledTasks = [];
        this.warpLevel = 0;
        this.timer = 0;
    }

    tick(dt) {
        this.timer += dt;

        for (let i = this.scheduledTasks.length - 1; i >= 0; i--) {
            let v = this.scheduledTasks[i];
            v[1] -= dt;

            if (v[1] <= 0) {
                this.scheduledTasks.splice(i, 1);
                this.runTask(v[0], dt);
            }
        }
    }

    runTask(task, arg) {
        var res = task.next(arg);
        if (res.done) return;
    
        var waitTime = res.value || 0;
        this.scheduledTasks.push([task, waitTime]);
    }

    get scene() {
        return this.scenes[this.sceneNum];
    }

    get stage() {
        return this.scene.stage;
    }

    go() {
        this.stop();
        this.stage.broadcast("message", "__shout__go__");
    }

    stop() {
        this.scheduledTasks = [];
    }

    pushWarp() {
        this.warpLevel++;
    }

    popWarp() {
        this.warpLevel--;
        if (this.warpLevel < 0) this.warpLevel = 0;
    }

    get warped() {
        return this.warpLevel > 0;
    }

    updateSize() {
        var width = this.stage.width;
        var height = this.stage.height;

        // update canvas
        this.canvas.width = width * window.devicePixelRatio;
        this.canvas.height = height * window.devicePixelRatio;
        this.canvas.style.width = `${width}px`;
        this.canvas.style.height = `${height}px`;
    }

    render() {
        var canvas = this.canvas;
        var ctx = canvas.getContext("2d");
        ctx.resetTransform();
        ctx.scale(window.devicePixelRatio, window.devicePixelRatio);

        // TODO make this an option
        ctx.imageSmoothingEnabled = true;

        ctx.fillStyle = "black";
        ctx.fillRect(0, 0, canvas.width, canvas.height);

        var scene = this.scene;
        var stage = scene.stage
        stage.render(canvas, ctx);
    }

    isKeyDown(k) {
        return this.keys.has(k);
    }

    keyDown(ev) {
        var map = KEY_MAPS[ev.code];
        
        if (map) {
            this.keys.add(map);
            this.stage.broadcast("keydown", "any key", map);
            this.stage.broadcast("keydown", map);
        } 
    }

    keyUp(ev) {
        var map = KEY_MAPS[ev.code];

        if (map) {
            this.keys.delete(map);
        }
    }

    mouseMove(ev) {
        var mouseX = ev.pageX - this.canvas.offsetLeft;
        var mouseY = ev.pageY - this.canvas.offsetTop;

        this.mouseX = mouseX - this.canvas.width / 2;
        this.mouseY = -(mouseY - this.canvas.height / 2);
    }

    mouseDown(ev) {
        this._mouseDown = true;
    }

    mouseUp(ev) {
        this._mouseDown = false;
    }
}

export { Project };